/*
 * $Id$
 *
 * Copyright 2006- Revolution Health Group.  All rights reserved.
 *
 * This software is the confidential and proprietary information
 * of Revolution Health Group.  (Confidential Information).
 * You shall not disclose such Confidential Information and shall
 * use it only in accordance with the terms of the license 
 * agreement you entered into with Revolution Health Group.
 */

package org.javason.util.spring;

import java.io.IOException;
import java.util.Properties;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
import org.springframework.core.io.Resource;


public class EnvAwarePropertyConfigurer extends PropertyPlaceholderConfigurer {
    public static final String VERSION = "$Rev$";
    private static final String DEPLOYMENT_ENV = "deployment.env";
  
	private static final Logger LOG = Logger.getLogger(EnvAwarePropertyConfigurer.class);

    // not available through super class. need to intercept it here
    protected Resource[] _locations;

    protected boolean _loadOneLocationOnly;
    
    public void setLocations(Resource locations[])
    {
        _locations = locations;
        super.setLocations(locations);
    }
    
    public void setLoadOneLocationOnly (boolean loadOneLocationOnly) {
        _loadOneLocationOnly = loadOneLocationOnly;
    }	
	
    /**
     * Default constructor
     */
    public EnvAwarePropertyConfigurer() {
        super();
    }
 
	/* (non-Javadoc)
	 * @see org.springframework.beans.factory.config.PropertyPlaceholderConfigurer#resolvePlaceholder(java.lang.String, java.util.Properties)
	 */
	@Override
	protected String resolvePlaceholder(String arg0, Properties arg1) {
		String prefix = System.getProperty(DEPLOYMENT_ENV); // assume we get this from an environment variable
		LOG.info(String.format("deployment.env is: %s", prefix));
		Properties newProp = replacePrefixedProperties(prefix, arg1);
		return super.resolvePlaceholder(arg0, newProp);
	}

	/**
	 * This method takes a Property file and uses the properties that start with the provided prefix
	 * plus a "." (such as "dev.url") and uses it's value as the default value for property "url".  This
	 * will allow different environments to be set.
	 * This method was separated out to make it testable.
	 * @param origProps
	 
	 */
	protected Properties replacePrefixedProperties(String prefix, Properties origProps) {
		Properties newProps = null;
	
		
		if (prefix != null && !prefix.equals("")){
			newProps = (Properties)origProps.clone();
			for (Object prop : origProps.keySet()){
	
				// this will put in the new value or replace the default value.
				if (((String)prop).startsWith(prefix)){
					String value = (String)origProps.getProperty((String)prop);
					newProps.put(((String)prop).replaceFirst(prefix+ ".", ""),value);
					newProps.remove(prop);
				} 
			}
		} else {
			// nothing to change
			newProps = origProps;
		}
		return newProps;
	}

	/**
     * load the property from the first location the file can be found. ignore errors from other locations. 
     */
    protected void loadProperties(Properties props) throws IOException {
        if (!_loadOneLocationOnly) {
            super.loadProperties(props);
            return;
        }
        
        if (_locations != null) {
            IOException ioe = null;
            boolean succeeded = false;
            try {
                for (Resource location : _locations) {
                    setLocation(location);
                    try {
                        super.loadProperties(props);
                        succeeded = true;
                        break;
                    } catch (IOException e) {
                    	LOG.debug("got exception while loading properties. trying the next location", e);
                        ioe = e;
                    }
                }
            } finally {
                // set the locations back
                setLocations(_locations);
            }
            if (!succeeded && ioe != null) {
                // throw the last exception
                throw ioe;
            }
        }
    }	
	
}
